package com.hixtrip.sample.infra;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hixtrip.sample.domain.inventory.repository.InventoryRepository;
import com.hixtrip.sample.infra.db.dataobject.Inventory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.ScriptSource;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.scripting.support.StaticScriptSource;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * infra层是domain定义的接口具体的实现
 */
@Component
public class InventoryRepositoryImpl implements InventoryRepository, InitializingBean {

    @Autowired
    private  RedisTemplate<String, Object> redisTemplate;
    private final String INVENTORY_KEY_PREFIX = "inventory:"; // 商品SKU ID 的Redis Key前缀

    private final DefaultRedisScript<Boolean> RESERVE_SCRIPT = new DefaultRedisScript<>();
    private final DefaultRedisScript<Boolean> COMMIT_SCRIPT = new DefaultRedisScript<>();

    public InventoryRepositoryImpl(RedisTemplate<String, Object> redisTemplate) throws IOException {


        // 初始化Lua脚本
        RESERVE_SCRIPT.setLocation(new ClassPathResource("preemptive-reserve.lua"));
        RESERVE_SCRIPT.setResultType(Boolean.class);

        COMMIT_SCRIPT.setLocation(new ClassPathResource("commit-preemptive-reserve.lua"));
        COMMIT_SCRIPT.setResultType(Boolean.class);
    }

    /**
     * 实际库存减N,预占库存加N
     * @param skuId id
     * @param quantity 购买数量
     * @return
     */
    @Override
    public boolean reservePreemptively(String skuId, Long quantity) {
        String inventoryKey = INVENTORY_KEY_PREFIX + skuId;
        return Boolean.TRUE.equals(redisTemplate.execute(RESERVE_SCRIPT, Collections.singletonList(inventoryKey), quantity));
    }

    /**
     * 预占库存减N，已售库存加N
     * @param skuId
     * @param quantity
     * @return
     */
    @Override
    public boolean commitPreemptiveReservation(String skuId, Long quantity) {
        String inventoryKey = INVENTORY_KEY_PREFIX + skuId;
        return Boolean.TRUE.equals(redisTemplate.execute(COMMIT_SCRIPT, Collections.singletonList(inventoryKey), quantity));
    }

    /**
     * 模拟数据 sku_id为4的库存情况
     */
    @Override
    public void afterPropertiesSet()  {

        Map<String, Long> map = new HashMap<>();
        //已占库存
        map.put("occupiedQuantity",10L);
        //预占库存
        map.put("withholdingQuantity",0L);
        //可售库存
        map.put("sellableQuantity",100L);

        redisTemplate.opsForHash().putAll(INVENTORY_KEY_PREFIX.concat("4"),map);

    }

    /**
     * 获取库存
     * @param  skuId id
     * @return boolean
     */
    @Override
    public Integer decrementSkuInventory(String skuId) {
         return (Integer) redisTemplate.opsForHash().get(INVENTORY_KEY_PREFIX.concat(skuId), "sellableQuantity");
    }

}
